CompletePasswordChange.php

<?php

namespace Tlf\User\Test;

class CompletePasswordChange extends \Tlf\User\GuiTester {

    ////////////
    //
    // Actions being tested here:
    // - GET password reset form
    // - POST password reset form (sends email to finish reset)
    // - GET complete reset form (enter new password)
    // - POST complete reset form  (update password in db)
    //
    // States being tested:
    // - user does not exist
    // - user is registered, but not activated
    // - user is registered and activated
    // - user is currently logged in vs not
    //
    //
    ////////////


    protected $page_message = 'An email has been sent to %s. Please check your email to finish resetting your password';

    protected function get_code($email = 'whatever'){
        $lib = new \Tlf\User\Lib($this->pdo());
        $user = $lib->user_from_email($email);
        $user->register('password placeholder');
        return $user->new_code('password_reset');
    }

    public function testPostNewPasswordThrottle(){
        $this->clear_email();
        $email = 'reed@post.newpassword.throttle';
        $lib = new \Tlf\User\Lib($this->pdo());
        $user = $this->get_active_user($email);

        $password = 'i am a Good New Password!3';
        $confirm_password = $password;

        $code = $user->new_code('password_reset');

        $response = $this->post('/user/complete.password_reset.'.$code.'/',
            ['email'=>$email,
            'password'=>$password,
            'password_confirm'=>$confirm_password.'password-mismatch',
            'test_spoof_ip'=>'post.new.password.throttle'
            ],
        );



        $response = $this->post('/user/complete.password_reset.'.$code.'/',
            ['email'=>$email,
            'password'=>$password,
            'password_confirm'=>$confirm_password,
            'test_spoof_ip'=>'post.new.password.throttle'
            ],
        );

        $this->str_contains($response,
            'Please wait 5 seconds before trying again.',
        );
        $this->str_not_contains(
            $response,
            '<form'
        );

    }

    public function testGetPasswordThrottle(){
        // $code = $this->get_code();
        $user = $this->get_active_user('reed@test.password_throttle');
        $code = $user->new_code('password_reset');
        $response = $this->get("/user/complete.password_reset.$code/",
            ['test_spoof_ip'=>'get.password.throttle']
        );

        echo $response;

        $this->str_contains(
            $response,
            '<form method="POST" action="/user/complete.password_reset.'.$code.'/">',
            'Set New Password',
        );
        
        $response = $this->get("/user/complete.password_reset.$code/",
            ['test_spoof_ip'=>'get.password.throttle']
        );

        echo $response;

        $this->str_contains($response,
            'Please wait 5 seconds before trying again.',
        );
        $this->str_not_contains(
            $response,
            '<form'
        );
    }

    public function testPostNewPasswordInactiveUser(){
        $email = 'reed@user.inactive.setpassword';
        $password = 'AbcdEfgh!1234';
        $code = $this->get_code($email);
        $response = $this->post("/user/complete.password_reset.$code/",
            ['email'=>$email,
            'password'=>$password,
            'password_confirm'=>$password,
            'test_spoof_ip'=>'post.newpassword.inactiveuser'
            ]
        );
        $this->str_contains($response,
            "Cannot complete password reset at this time because registration is not complete for your account. Please check your email for a registration confirmation link.",
        );
        $this->str_not_contains($response, '<form');
    }
    public function testPostNewPasswordConfirmationInvalid(){
        $email = 'reed@mismatch.setpassword';
        $password = 'AbcdEfgh!1234';
        $code = $this->get_code($email);
        $response = $this->post("/user/complete.password_reset.$code/",
            ['email'=>$email,
            'password'=>$password,
            'password_confirm'=>'oops, mismatch',
            'test_spoof_ip'=>'post.newpassword.confirmationinvalid'
            ]
        );
        $this->str_contains($response,
            "The confirmation password you entered did not match.",
            '<form',
        );

    }
    public function testPostNewPasswordCodeInvalid(){
        $email = 'reed@post.reset.invalidcode';
        $user = $this->get_active_user($email, 'abc');
        $code = 'badcode1';
        $response = $this->post('/user/complete.password_reset.'.$code.'/',
            ['test_spoof_ip'=>'post.newpassword.codeinvalid']
        );

        $this->str_contains(
            $response,
            "Password reset code '$code' is not valid.",
        );
        $this->str_not_contains($response, '<form', $email);
    }
    public function testPostNewPasswordEmailInvalid(){
        $code = $this->get_code('not-an-email');
        $response = $this->post("/user/complete.password_reset.$code/",
            ['email'=>'not-an-email',
            'test_spoof_ip'=>'post.newpassword.emailinvalid'
            ]
        );
        $this->str_contains($response,
            "'not-an-email' is not a valid email address. Please try again.",
            '<form',
        );
        // $this->str_contains($response, '<form');
        echo $response;
    }
    public function testPostNewPasswordInsecure(){
        $email = 'reed@insecure.setpassword';
        $code = $this->get_code($email);
        $response = $this->post("/user/complete.password_reset.$code/",
            ['email'=>$email,
            'password'=>'badpass',
            'test_spoof_ip'=>'post.newpassword.insecure'
            ]
        );
        $this->str_contains($response,
            "The password you entered does not meet our minimum requirements. Please try again.",
            '<form',
        );
    }

    public function testPostNewPasswordWrongEmail(){
        $this->clear_email();
        $email = 'reed@post.mismatchemail';
        $lib = new \Tlf\User\Lib($this->pdo());
        $user = $this->get_active_user($email);

        $password = 'i am a Good New Password!3';
        $confirm_password = $password;

        $code = $user->new_code('password_reset');

        $response = $this->post('/user/complete.password_reset.'.$code.'/',
            ['email'=>'reed@post.thisemaildoesntmatch',
            'password'=>$password,
            'password_confirm'=>$confirm_password,
            'test_spoof_ip'=>'post.newpassword.wrongemail'
            ],
        );

        $this->str_contains($response,
            "We could not update your password. Either the code you're using is invalid or you've entered the wrong email address. Please try again.",
        );

        $this->str_contains($response,
            '<form'
        );

        $mail_msg = $this->get_email();
        $this->compare('--no-email--', $mail_msg);

    }

    public function testPostNewPassword(){
        $this->clear_email();
        $email = 'reed@post.newpassword';
        $lib = new \Tlf\User\Lib($this->pdo());
        $user = $this->get_active_user($email);

        $password = 'i am a Good New Password!3';
        $confirm_password = $password;

        $code = $user->new_code('password_reset');

        $response = $this->post('/user/complete.password_reset.'.$code.'/',
            ['email'=>$email,
            'password'=>$password,
            'password_confirm'=>$confirm_password,
            'test_spoof_ip'=>'post.new.password'
            ],
        );
//
        // echo $response;
        // exit;

        $this->str_contains($response,
            'Your password has been updated! Please <a href="/user/login/">Log in here</a> with your new password.'
        );
        // echo $response;
        // exit;

        $this->str_not_contains($response,
            '<form'
        );

        $mail_msg = $this->get_email();

        $this->compare("Your password for <a href=\"http://create.localhost\">http://create.localhost</a> was changed.",
            $mail_msg
        );
    }

    public function testPostInvalidCode(){
        $response = $this->post('/user/complete.password_reset.badcode2/',
            [
                'email'=>'for-the-throttle',
                'test_spoof_ip'=>'post.invalid.codeyes'
            ]
        );

        $this->str_contains($response,
            "Password reset code 'badcode2' is not valid.",
        );
        echo $response;

    }

    public function testCompleteResetFormBeforeRegisterComplete(){
        $email = 'reed@inactive.completereset';
        $lib = new \Tlf\User\Lib($this->pdo());
        $user = $lib->user_from_email($email);
        $user->register('abc');
        $user = $lib->user_from_email($email);
        $this->test('user is registered, not active');
        $this->is_true($user->is_registered());
        $this->is_false($user->is_active());

        $reset_code = $user->new_code('password_reset');

        $response = $this->get('/user/complete.password_reset.'.$reset_code.'/',
            ['test_spoof_ip'=>3]
        );

        echo $response;
        // exit;

        $this->str_contains($response,
            'Cannot complete password reset at this time because registration is not complete for your account.',
            'Please check your email for an account registration email with a link to complete registration.',
        );

        // echo $response;
        // exit;

        $this->str_not_contains($response, '<form', $email);
        
    }

    public function testCompleteResetFormBadCode(){
// phptest -test PostNewPasswordInactiveUser -test PostNewPasswordConfirmationInvalid -test PostNewPasswordCodeInvalid -test PostNewPasswordEmailInvalid -test PostNewPasswordInsecure -test PostNewPasswordWrongEmail -test PostNewPassword -test PostInvalidCode -test CompleteResetFormBeforeRegisterComplete -test CompleteResetFormBadCode

        $email = 'reed@get.reset.invalidcode';
        $user = $this->get_active_user($email, 'abc');
        $code = 'badcode3';
        $response = $this->get('/user/complete.password_reset.'.$code.'/',
            ['test_spoof_ip'=>'copmlete.reset.form.bad.code']
        );

        // echo $response;
        // exit;

        $this->str_contains(
            $response,
            "Password reset code '$code' is not valid.",
        );
        $this->str_not_contains($response, '<form', $email);

    }

    public function testCompleteResetForm(){
        $email = 'reed@complete.reset.form';
        $user = $this->get_active_user($email, 'abc');
        $code = $user->new_code('password_reset');
        $response = $this->get('/user/complete.password_reset.'.$code.'/',
            ['test_spoof_ip'=>1]
        );

        echo $response;

        $this->str_contains(
            $response,
            '<form method="POST" action="/user/complete.password_reset.'.$code.'/">',
            'Set New Password',
        );
    }

}